package jmine.tec.utils.math;

import java.math.BigDecimal;
import java.math.MathContext;

/**
 * Classe utilitaria para guardar algumas operacoes com {@link BigDecimal}
 * 
 * @author takeshi
 */
public final class MathUtils {

    /**
     * Private c'tor
     */
    private MathUtils() {
    }

    private static final int DEFAULT_NUMBER_OF_STEPS = 100;

    /**
     * Calcula a n-esima raiz de um valor atraves. O 'steps' representa o numero de iteracoes do algoritmo. Um valor proximo a
     * {@link #DEFAULT_NUMBER_OF_STEPS} deve devolver um numero na precisao {@link #MAX_PRECISION}
     * 
     * @param value o radicando
     * @param n o indice
     * @param steps o numero de passos da iteracao
     * @return {@link BigDecimal}
     */
    public static BigDecimal nthRoot(BigDecimal value, int n, int steps) {
        final int n11 = n - 1;
        final BigDecimal n1 = BigDecimal.valueOf(n11);
        final BigDecimal outer = BigDecimal.ONE.divide(new BigDecimal(n), MathContext.DECIMAL128);
        BigDecimal soFar = BigDecimal.ONE;
        for (int i = 0; i < steps; i++) {
            soFar = step(soFar, n1, outer, value, n11);
        }
        return soFar;
    }

    /**
     * Equivalente a chamar {@link #nthRoot(BigDecimal, int, int)} com {@link #DEFAULT_NUMBER_OF_STEPS} como numero de iteracoes
     * 
     * @param value o radicando
     * @param n o indice
     * @return {@link BigDecimal}
     */
    public static BigDecimal nthRoot(BigDecimal value, int n) {
        return nthRoot(value, n, DEFAULT_NUMBER_OF_STEPS);
    }

    /**
     * @param prev o resultado da iteracao anterior
     * @param n1 n-1 decimal
     * @param outer 1/n
     * @param a o radicando
     * @param n11 n-1 inteiro
     * @return {@link BigDecimal}
     */
    private static BigDecimal step(BigDecimal prev, BigDecimal n1, BigDecimal outer, BigDecimal a, int n11) {
        return outer.multiply((n1.multiply(prev, MathContext.DECIMAL128)).add(a.divide(prev.pow(n11), MathContext.DECIMAL128)),
                MathContext.DECIMAL128);
    }
}
